package com.lagou.ipersistence.executor;

import com.lagou.ipersistence.executor.statement.StatementHandler;
import com.lagou.ipersistence.mapping.BoundSql;
import com.lagou.ipersistence.mapping.MappedStatement;
import com.lagou.ipersistence.mapping.ParameterMapping;
import com.lagou.ipersistence.session.Configuration;
import com.lagou.ipersistence.session.ResultHandler;
import com.lagou.ipersistence.session.RowBounds;
import com.lagou.ipersistence.transaction.Transaction;
import com.lagou.ipersistence.util.GenericTokenParser;
import com.lagou.ipersistence.util.ParameterMappingTokenHandler;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Yan Jiahong
 * Created 2020/11/8
 */
public class SimpleExecutor extends BaseExecutor {
    
    public SimpleExecutor(Configuration configuration, Transaction transaction) {
        super(configuration, transaction);
    }

//    @Override
//    public <E> List<E> query(Configuration cfg, MappedStatement mst, Object... params) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IntrospectionException, InstantiationException, InvocationTargetException {
//        // 获取连接
//        Connection connection = cfg.getDataSource().getConnection();
//        // 获取到Sql语句
//        // select * from t_user where id = #{id}
//        String sql = mst.getSql();
//        BoundSql boundSql = getBoundSql(sql);
//
//        //3.取预处理对象
//        PreparedStatement pst = connection.prepareStatement(boundSql.getSql());
//        String parameterType = mst.getParameterType();
//        String resultType = mst.getResultType();
//        Class<?> parameterTypeClass = getClassType(parameterType);
//        Class<?> resultTypeClass = getClassType(resultType);
//
//        // 4.设置参数
//        for (int i = 0; i < boundSql.getParameterMappings().size(); i++) {
//            ParameterMapping pm = boundSql.getParameterMappings().get(i);
//            // 参数名
//            String content = pm.getContent();
//            // todo 反射中的getField和getDeclaredField有什么区别?
//            Field declaredField = parameterTypeClass.getDeclaredField(content);
//            declaredField.setAccessible(true);
//            Object o = declaredField.get(params[0]);
//            pst.setObject(i + 1, o);
//        }
//
//        // 5.执行SQL
//        ResultSet rs = pst.executeQuery();
//        List<Object> objects = new ArrayList<>();
//        // 6.封装结果集
//        while (rs.next()) {
//            Object resultTypeObj = resultTypeClass.newInstance();
//            ResultSetMetaData meta = rs.getMetaData();
//            for (int i = 1; i < meta.getColumnCount() + 1; i++) {
//                // 列名
//                String colName = meta.getColumnName(i);
//                // 值
//                Object val = rs.getObject(colName);
//                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(colName, resultTypeClass);
//                Method writeMethod = propertyDescriptor.getWriteMethod();
//                writeMethod.invoke(resultTypeObj, val);
//            }
//            objects.add(resultTypeObj);
//        }
//        return (List<E>) objects;
//    }
    
    @Override
    protected <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler<?> resultHandler, BoundSql boundSql) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds,
                    resultHandler, boundSql);
            stmt = prepareStatement(handler);
            return handler.query(stmt, resultHandler);
        } finally {
            closeStatement(stmt);
        }
    }
    
    @Override
    protected int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
        Statement stmt = null;
        try {
            Configuration configuration = ms.getConfiguration();
            StatementHandler handler = configuration.newStatementHandler(this, ms, parameter,
                    RowBounds.DEFAULT, null, null);
            stmt = prepareStatement(handler);
            return handler.update(stmt);
        } finally {
            closeStatement(stmt);
        }
    }
    
    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if (parameterType != null) {
            return Class.forName(parameterType);
        }
        return null;
    }
    
    private Statement prepareStatement(StatementHandler handler) throws SQLException {
        Connection connection = getConnection();
        Statement stmt = handler.prepare(connection, transaction.getTimeout());
        handler.parameterize(stmt);
        return stmt;
    }
}
